別AWSアカウントにあるECRリポジトリへアクセスする方法

別AWSアカウントにあるECRリポジトリへアクセスする方法

Clock Icon2024.10.27

しばたです。

あるAWSアカウント内のリソース(EC2など)から別アカウントにあるECRリポジトリに対してアクセスする際は、

  1. ECRリポジトリのリポジトリポリシー設定
  2. ECRへアクセスするリソース側の権限設定

を行う必要がありますが、DevelopersIOに私が欲しい感じの解説記事が無かったので自分で書くことにしました。

0. 検証環境

本記事では下図の構成を検証環境として用意しました。

how-to-setup-cross-account-ecr-repository-access-00

2つのAWSアカウントを用意し、その内一つのアカウント(111111111111)にECRリポジトリを作成します。
もう一つのアカウント(222222222222)にDockerをインストールしたEC2インスタンスを用意しECRリポジトリ内のイメージに対してPushとPullを行っていきます。

今回は

  • 両アカウントとも東京リージョンを使用
  • EC2は本日時点で最新のAmazon Linux 2023環境
  • EC2インスタンスからインターネットアクセス可能

という条件で動作確認しています。

1. ECR側設定 (リポジトリポリシー設定)

はじめにAWSアカウント(111111111111)でECRリポジトリを作成しておきます。
今回はAWS CloudShellからtest-repoという名前のリポジトリを作成しています。

# Account : 111111111111 でECRリポジトリ作成
aws ecr create-repository --repository-name 'test-repo'

how-to-setup-cross-account-ecr-repository-access-01

ここから別アカウントからのアクセスを許可するために適切なリポジトリポリシーを設定します。

今回設定するリポジトリポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPushPullFromOtherAccount",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::222222222222:root"
      },                     
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload"
      ]
    }
  ]
}

今回は上記参考ドキュメントに倣ったポリシーを設定しますが、環境や用途に応じてPrincipal指定や許可するActionを変更してください。

Principalは許可する相手を指定するのでアカウント(222222222222)にします。
Actionは基本的に

  • Pull用
    • ecr:GetDownloadUrlForLayer
    • ecr:BatchGetImage
  • Push用
    • ecr:BatchCheckLayerAvailability
    • ecr:PutImage
    • ecr:InitiateLayerUpload
    • ecr:UploadLayerPart
    • ecr:CompleteLayerUpload

を許可すれば事足りると思います。
(足りない場合は適宜追加のActionを許可してください。)

マネジメントコンソールからリポジトリを選択し、アクションの「許可」を選んでリポジトリポリシーの編集画面を開きます。
そして「ポリシーJSONの編集」を選び、

how-to-setup-cross-account-ecr-repository-access-02

前掲のJSONポリシーを転記して保存します。

how-to-setup-cross-account-ecr-repository-access-03

設定内容が反映されていればOKです。

how-to-setup-cross-account-ecr-repository-access-04

2. EC2側設定 (IAMポリシー設定)

次にAWSアカウント(22222222222)でEC2に適用するIAMポリシー設定を行います。
リポジトリポリシーはリポジトリ側から見たアクセス制御でしたが、こちらのIAMポリシーは「EC2等のアクセス元がどのActionを実行可能か」を指定する形になります。

今回は参考ドキュメントを元に以下の権限を持ったポリシーを作成します。

IAMポリシーの設定内容
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAccessToOtherAccountECR",
      "Effect": "Allow",
      "Action": [
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "ecr:BatchCheckLayerAvailability",
        "ecr:PutImage",
        "ecr:InitiateLayerUpload",
        "ecr:UploadLayerPart",
        "ecr:CompleteLayerUpload"
      ],
      "Resource": "arn:aws:ecr:ap-northeast-1:1111111111:repository/test-repo"
    },
    {
      "Sid": "GetAuthorizationToken",
      "Effect": "Allow",
      "Action": "ecr:GetAuthorizationToken",
      "Resource": "*"
    }
  ]
}

リポジトリポリシーに合わせて次のActionを許可しています。

  • Pull用
    • ecr:GetDownloadUrlForLayer
    • ecr:BatchGetImage
  • Push用
    • ecr:BatchCheckLayerAvailability
    • ecr:PutImage
    • ecr:InitiateLayerUpload
    • ecr:UploadLayerPart
    • ecr:CompleteLayerUpload

これらのActionはリソース指定が可能なためAWSアカウント(111111111111)のtest-repoに限定した許可を与えています。
残りの

  • AWS認証用
    • ecr:GetAuthorizationToken

はリソースを限定することが出来ないため*指定の許可としています。

ポリシーの作成方法はなんでも構いませんが、今回はマネジメントコンソールからallow-access-to-other-account-ecr-policyという名前で作成しました。

how-to-setup-cross-account-ecr-repository-access-05

さらに今回はEC2からアクセスするので、追加でtest-ec2-roleという名前のIAMロールを作成し、allow-access-to-other-account-ecr-policyポリシーを割り当てています。

how-to-setup-cross-account-ecr-repository-access-06

IAMロールの作成手順は割愛します。

3. EC2側設定 (内部設定など)

EC2インスタンス自体はAmazon Linux 2023でt3.smallのインスタンスを作成し、IAMロールtest-ec2-roleを割り当てています。

how-to-setup-cross-account-ecr-repository-access-07

加えて初期設定として以下の手順でDockerをインストール済みです。

EC2初期設定
sudo dnf update -y

sudo dnf install -y docker
sudo systemctl start docker
sudo usermod -a -G docker ec2-user
sudo usermod -a -G docker ssm-user

今回はDocker Client 25.0.5, Docker Server 25.0.6がインストールされました。

# インストールしたDockerのバージョンを確認
$ docker version
Client:
 Version:           25.0.5
 API version:       1.44
 Go version:        go1.22.5
 Git commit:        5dc9bcc
 Built:             Wed Aug 21 00:00:00 2024
 OS/Arch:           linux/amd64
 Context:           default

Server:
 Engine:
  Version:          25.0.6
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.22.5
  Git commit:       b08a51f
  Built:            Wed Aug 21 00:00:00 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.22
  GitCommit:        7f7fdf5fed64eb6a7caf99b3e12efcf9d60e311c
 runc:
  Version:          1.1.14
  GitCommit:        2c9f5602f0ba3d9da1c2596322dfc4e156844890
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

4. 動作確認

ここから実際に動作確認をしていきます。
SSM Sessionを使ってEC2内部にログインし各種コマンドを実行します。

4-1. リポジトリへのPush

はじめにtest-repoリポジトリに対して適当なDockerイメージをPushします。

前準備として適当なDockerfileからDockerイメージを作成します。
Dockerfileは単体でビルド可能なものであればなんでも良いのですが、今回は私個人のGitHubリポジトリにある以下のDockerfile[1]を使うことにします。

curlコマンド等でDockerfileをダウンロードしておき、

# 動作確認用Dockerfileをダウンロード
curl -O https://raw.githubusercontent.com/stknohg/aws-cli-eq-pwsh/refs/heads/main/Dockerfile

docker buildコマンドでイメージを作成、ECRへのPush用にタグ付けまで行っておきます。
ここは一般的なECRへのPush方法と同じです。

# Dockerイメージ作成 + タグ付け
docker build -t test-repo .
docker tag test-repo:latest 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest

結果はこんな感じです。

# 作成されたイメージを確認
$ docker images
REPOSITORY                                                    TAG       IMAGE ID       CREATED          SIZE
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo   latest    0f196693ce1c   33 seconds ago   1.45GB
test-repo                                                     latest    0f196693ce1c   33 seconds ago   1.45GB

続けてこのイメージをECRリポジトリにPushします。
docker logindocker pushコマンドの組み合わせ自体は通常のECRへのPushと同じですが、リポジトリ指定が別アカウント(111111111111)になります。

# ECRへのPush 
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest

ポリシー設定等に問題がなければエラー無くPushされ、次の様な結果になります。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ssm-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

$ docker push 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
The push refers to repository [111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo]
3675938c6474: Pushed
eed3f3c893c9: Pushed
7d42b235083d: Pushed
41ee9381f1ba: Pushed
1b9b7346fee7: Pushed
latest: digest: sha256:1f1d9c0668b54bd4f4aab272ff9599dd9056ebd23ffc29782dd9b5f07f9fef1b size: 1379

マネジメントコンソールからECRリポジトリを確認するとちゃんとイメージが保存されていました。

how-to-setup-cross-account-ecr-repository-access-11

how-to-setup-cross-account-ecr-repository-access-12

4-2. リポジトリからのPull

次にこのイメージをPullしていきます。

動作確認のため、一旦ローカルにあるDockerイメージを全て削除してキャッシュもクリアしておきます。

# 既存イメージの削除とキャッシュのクリア
docker images -q | xargs docker rmi -f {}
docker system prune --volumes -f
# 保存された認証情報も削除
rm /home/ssm-user/.docker/config.json

docker imagesコマンドでイメージが無くなっていることを確認しておきます。

# ローカルにイメージが無い状態に
$ docker images
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE

この状態でECRリポジトリからイメージをPullします。

# ECRからPullする
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest

こちらもポリシー設定等に問題がなければエラー無くPullされて以下の様になります。[2]

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ssm-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

$ docker pull 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
latest: Pulling from test-repo762bedf4b1b7: Already exists
57ed3936f2b8: Already exists
8889f02ed290: Already exists
e4cc63e7c8d3: Already exists
fdba7b911ffb: Already exists
Digest: sha256:1f1d9c0668b54bd4f4aab272ff9599dd9056ebd23ffc29782dd9b5f07f9fef1b
Status: Downloaded newer image for 111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo:latest

最後にdocker imagesコマンドでイメージがあることを確認しておきます。

# Pullした結果を確認
$ docker images
REPOSITORY                                                    TAG       IMAGE ID       CREATED          SIZE
111111111111.dkr.ecr.ap-northeast-1.amazonaws.com/test-repo   latest    0f196693ce1c   23 minutes ago   1.45GB

最後に

以上となります。

今回はEC2からのアクセスを試しましたが、他リソースからアクセスする場合においても基本的な部分は変わらないので参考になると思います。
本記事の内容が皆さんの役に立てば幸いです。

脚注
  1. このDockerfile自体は開発環境を作るものです。他に良さそうな例を思いきませんでした... ↩︎

  2. ちょっとキャッシュの消し方に問題があった様ですが、結果に影響を与えるものではないと思うので本記事では無視します。 ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.